/*
 ******************************************************************************
 *  Java Signal Framework for routing java objects. 
 *  Copyright (C) 2008  Manuel Stahl (thymythos@web.de)
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 ****************************************************************************** 
 */
package org.tru42.signal.model;

import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;

import org.tru42.signal.lang.ConnectException;
import org.tru42.signal.lang.ISignal;
import org.tru42.signal.lang.ISink;
import org.tru42.signal.lang.SObject;


public class SignalDiagram extends SObject {
	
	private int nameIndex = 0;
	
	private final LinkedList<IModelChangeListener> listeners = new LinkedList<IModelChangeListener>();
	
	private final HashMap<String, ISignalProcessor> processors = new HashMap<String, ISignalProcessor>();
	
	public SignalDiagram() {
		name = "Model";
	}
	
	public void addSignalProcessor(ISignalProcessor proc) {
		if(proc.getName() == null)
			proc.setName(proc.getClass().getSimpleName() + "(" + (nameIndex++) + ")");
		proc.setModel(this);
		processors.put(proc.getName(), proc);
		for(IModelChangeListener l: listeners)
			l.processorAdded(proc);
	}
	
	public void deleteSignalProcessor(ISignalProcessor proc) {
		proc.dispose();
		processors.remove(proc.getName());
		informListeners(proc);
	}

	public void renameSignalProcessor(ISignalProcessor proc, String newName) {
		if(processors.containsValue(proc)) {
			processors.remove(proc.getName());
			proc.setName(newName);
			processors.put(newName, proc);
			informListeners(proc);
		}
	}
	
	public void connect(ISignal signal, ISink sink) throws ConnectException {
		sink.connect(signal);
		informListeners(sink);
		informListeners(signal);
	}
		
	public void disconnect(Sink sink) {
		ISignal signal = sink.getSignal();
		sink.disconnectSignal();
		informListeners(sink);
		if(signal != null) {
			signal.disconnectSink(sink);
			informListeners(signal);
		}
	}
	
	public void disconnect(ISignal signal) {
		Sink[] sinks = signal.getConnectedSinks();
		for(Sink sink: sinks)
			sink.disconnectSignal();	// TODO: inform listener
		signal.disconnectSinks();
		informListeners(signal);
	}
	
	public ISignalProcessor getSignalProcessorByName(String name) {
		return processors.get(name);
	}
	
	public Collection<ISignalProcessor> getSignalProcessors() {
		return processors.values();
	}
	
	@Override
	public ISignal[] getSignals() {
		LinkedList<ISignal> signals = new LinkedList<ISignal>();
		for(ISignalProcessor p: processors.values())
			for(ISignal signal: p.getSignals())
			signals.add(signal);
		
		return signals.toArray(new ISignal[signals.size()]);
	}

	@Override
	public void dispose() {
		for(ISignalProcessor p: processors.values())
			p.dispose();
	}
	
	public void registerModelChangeListener(IModelChangeListener listener) {
		listeners.add(listener);
	}

	public void deregisterModelChangeListener(IModelChangeListener listener) {
		listeners.remove(listener);
	}
		
	private void informListeners(Object obj) {
		for(IModelChangeListener l: listeners)
			l.modelChanged(obj);
	}

}
